\ The Rest is Silence 03Apr84map************************************************************* ************************************************************* *** *** *** Please direct all questions, comments, and *** *** miscellaneous personal abuse to: *** *** *** *** Henry Laxen or Michael Perry *** *** 1259 Cornell Avenue 1125 Bancroft Way *** *** Berkeley, California Berkeley, California *** *** 94706 94702 *** *** *** ************************************************************* ************************************************************* \ Target System Setup 24Apr84mapONLY FORTH ' NLOAD IS LOAD META ALSO FORTH 256 DP-T ! HERE 12000 + ' TARGET-ORIGIN >BODY ! IN-META 2 92 THRU ( System Source Screens ) CR .( Unresolved references: ) CR .UNRESOLVED CR .( Statistics: ) CR .( Last Host Address: ) [FORTH] HERE U. CR .( First Target Code Address: ) META 256 THERE U. CR .( Last Target Code Address: ) META HERE-T THERE U. CR CR META 256 THERE HERE-T ( MS-DOS only ) ONLY FORTH ALSO DOS ' NOOP IS HEADER ONLY FORTH ALSO DOS SAVE A:KERNEL.COM FORTH \ ONLY FORTH ALSO DOS SAVE A:KERNEL.CMD FORTH CR .( Now return to the DOS and type: ) CR .( KERNEL EXTEND86.BLK <CR> ) CR .( OK <CR> ) \ Declare the Forward References and Version # 04Apr84map: ]] ] ; : [[ [COMPILE] [ ; FORTH IMMEDIATE META FORWARD: DEFINITIONS FORWARD: [ \ Boot up Vectors and NEXT Interpreter 04OCT83HHLASSEMBLER LABEL ORIGIN HERE 8000 + #) JMP \ jump to cold start: will be patched HERE 8000 + #) JMP \ jump to warm start: will be patched LABEL DPUSH DX PUSH LABEL APUSH AX PUSH LABEL >NEXT AX LODS AX W MOV 0 [W] JMP H: 2PUSH META ASSEMBLER DPUSH #) JMP ; H: 1PUSH META ASSEMBLER APUSH #) JMP ; H: NEXT META ASSEMBLER >NEXT #) JMP ; HERE-T DUP 100 + CURRENT-T ! ( harmless ) VOCABULARY FORTH FORTH DEFINITIONS 0 OVER 2+ !-T ( link ) DUP 2+ SWAP 16 + !-T ( thread ) IN-META \ Run Time Code for Defining Words 13Apr84mapASSEMBLER LABEL NEST W INC W INC RP DEC RP DEC IP 0 [RP] MOV W IP MOV NEXT META CODE EXIT (S -- ) 0 [RP] IP MOV RP INC RP INC NEXT END-CODE CODE UNNEST ' EXIT @-T ' UNNEST !-T END-CODE ASSEMBLER LABEL DODOES SP RP XCHG IP PUSH SP RP XCHG IP POP W INC W INC W PUSH NEXT LABEL DOCREATE W INC W INC W PUSH NEXT META \ Run Time Code for Defining Words 11OCT83HHLVARIABLE UP LABEL DOCONSTANT W INC W INC 0 [W] AX MOV 1PUSH END-CODE LABEL DOUSER-VARIABLE W INC W INC 0 [W] AX MOV UP #) AX ADD 1PUSH END-CODE CODE (LIT) (S -- n ) AX LODS 1PUSH END-CODE \ Meta Defining Words 07SEP83HHLT: LITERAL (S n -- ) [TARGET] (LIT) ,-T T; T: DLITERAL (S d -- ) [TARGET] (LIT) ,-T [TARGET] (LIT) ,-T T; T: ASCII (S -- ) [COMPILE] ASCII [[ TRANSITION ]] LITERAL [META] T; T: ['] (S -- ) 'T >BODY @ [[ TRANSITION ]] LITERAL [META] T; : CONSTANT (S n -- ) RECREATE [[ ASSEMBLER DOCONSTANT ]] LITERAL ,-T DUP ,-T CONSTANT ; \ Identify numbers and forward References 06Apr84mapFORWARD: <(;CODE)> T: DOES> (S -- ) [FORWARD] <(;CODE)> HERE-T ( DOES-OP ) 232 C,-T [[ ASSEMBLER DODOES ]] LITERAL HERE 2+ - ,-T T; : NUMERIC (S -- ) [FORTH] HERE [META] NUMBER DPL @ 1+ IF [[ TRANSITION ]] DLITERAL [META] ELSE DROP [[ TRANSITION ]] LITERAL [META] THEN ; : UNDEFINED (S -- ) HERE-T 0 ,-T IN-FORWARD [FORTH] CREATE [META] TRANSITION [FORTH] , FALSE , [META] DOES> FORWARD-CODE ; \ Meta Compiler Compiling Loop 04MAR83HHL[FORTH] VARIABLE T-IN META : ] (S -- ) STATE-T ON IN-TRANSITION BEGIN >IN @ T-IN ! DEFINED IF EXECUTE ELSE COUNT NUMERIC? IF NUMERIC ELSE T-IN @ >IN ! UNDEFINED THEN THEN STATE-T @ 0= UNTIL ; T: [ (S -- ) IN-META STATE-T OFF T; T: ; (S -- ) [TARGET] UNNEST [[ TRANSITION ]] [ T; : : (S -- ) TARGET-CREATE [[ ASSEMBLER NEST ]] LITERAL ,-T ] ; \ Run Time Code for Control Structures 04OCT83HHLCODE BRANCH (S -- ) LABEL BRAN1 0 [IP] IP MOV NEXT END-CODE CODE ?BRANCH (S f -- ) AX POP AX AX OR BRAN1 JE IP INC IP INC NEXT END-CODE \ Meta Compiler Branching Words 01AUG83HHLT: BEGIN ?<MARK T; T: AGAIN [TARGET] BRANCH ?<RESOLVE T; T: UNTIL [TARGET] ?BRANCH ?<RESOLVE T; T: IF [TARGET] ?BRANCH ?>MARK T; T: THEN ?>RESOLVE T; T: ELSE [TARGET] BRANCH ?>MARK 2SWAP ?>RESOLVE T; T: WHILE [[ TRANSITION ]] IF T; T: REPEAT 2SWAP [[ TRANSITION ]] AGAIN THEN T; \ Run Time Code for Control Structures 04OCT83HHLCODE (LOOP) (S -- ) 1 # AX MOV LABEL PLOOP AX 0 [RP] ADD BRAN1 JNO 6 # RP ADD IP INC IP INC NEXT END-CODE CODE (+LOOP) (S n -- ) AX POP PLOOP #) JMP END-CODE \ Run Time Code for Control Structures 11OCT83HHLHEX CODE (DO) (S l i -- ) AX POP BX POP LABEL PDO RP DEC RP DEC 0 [IP] DX MOV DX 0 [RP] MOV IP INC IP INC 8000 # BX ADD RP DEC RP DEC BX 0 [RP] MOV BX AX SUB RP DEC RP DEC AX 0 [RP] MOV NEXT END-CODE DECIMAL CODE (?DO) (S l i -- ) AX POP BX POP AX BX CMP PDO JNE 0 [IP] IP MOV NEXT END-CODE : BOUNDS (S adr len -- lim first ) OVER + SWAP ; \ Meta compiler Branching & Looping 01AUG83HHLT: ?DO [TARGET] (?DO) ?>MARK T; T: DO [TARGET] (DO) ?>MARK T; T: LOOP [TARGET] (LOOP) 2DUP 2+ ?<RESOLVE ?>RESOLVE T; T: +LOOP [TARGET] (+LOOP) 2DUP 2+ ?<RESOLVE ?>RESOLVE T; \ Execution Control 04OCT83HHLASSEMBLER >NEXT META CONSTANT >NEXT CODE EXECUTE (S cfa -- ) W POP 0 [W] JMP END-CODE CODE PERFORM (S addr-of-cfa -- ) W POP 0 [W] W MOV 0 [W] JMP END-CODE LABEL DODEFER (S -- ) W INC W INC 0 [W] W MOV 0 [W] JMP END-CODE LABEL DOUSER-DEFER W INC W INC 0 [W] AX MOV UP #) AX ADD AX W MOV 0 [W] W MOV 0 [W] JMP END-CODE CODE GO (S addr -- ) RET END-CODE CODE NOOP NEXT END-CODE CODE PAUSE NEXT END-CODE \ Execution Control 11OCT83HHLCODE I (S -- n ) 0 [RP] AX MOV 2 [RP] AX ADD 1PUSH END-CODE CODE J (S -- n ) 6 [RP] AX MOV 8 [RP] AX ADD 1PUSH END-CODE DECIMAL CODE (LEAVE) (S -- ) LABEL PLEAVE 4 # RP ADD 0 [RP] IP MOV RP INC RP INC NEXT END-CODE CODE (?LEAVE) (S f -- ) AX POP AX AX OR PLEAVE JNE NEXT END-CODE T: LEAVE [TARGET] (LEAVE) T; T: ?LEAVE [TARGET] (?LEAVE) T; \ 16 and 8 bit Memory Operations 22Aug83mapCODE @ (S addr -- n ) BX POP 0 [BX] PUSH NEXT END-CODE CODE ! (S n addr -- ) BX POP 0 [BX] POP NEXT END-CODE CODE C@ (S addr -- char ) BX POP AX AX SUB 0 [BX] AL MOV 1PUSH END-CODE CODE C! (S char addr -- ) BX POP AX POP AL 0 [BX] MOV NEXT END-CODE \ Block Move Memory Operations 11OCT83HHLCODE CMOVE (S from to count -- ) CLD IP BX MOV DS AX MOV AX ES MOV CX POP DI POP IP POP REP BYTE MOVS BX IP MOV NEXT END-CODE CODE CMOVE> (S from to count -- ) STD IP BX MOV DS AX MOV AX ES MOV CX POP CX DEC DI POP IP POP CX DI ADD CX IP ADD CX INC REP BYTE MOVS BX IP MOV CLD NEXT END-CODE \ 16 bit Stack Operations 22Aug83mapCODE SP@ (S -- n ) SP AX MOV 1PUSH END-CODE CODE SP! (S n -- ) SP POP NEXT END-CODE CODE RP@ (S -- addr ) RP AX MOV 1PUSH END-CODE CODE RP! (S n -- ) RP POP NEXT END-CODE \ 16 bit Stack Operations 22Aug83mapCODE DROP (S n1 -- ) AX POP NEXT END-CODE CODE DUP (S n1 -- n1 n1 ) AX POP AX PUSH 1PUSH END-CODE CODE SWAP (S n1 n2 -- n2 n1 ) DX POP AX POP 2PUSH END-CODE CODE OVER (S n1 n2 -- n1 n2 n1 ) DX POP AX POP AX PUSH 2PUSH END-CODE \ 16 bit Stack Operations 22Aug83mapCODE TUCK (S n1 n2 -- n2 n1 n2 ) AX POP DX POP AX PUSH 2PUSH END-CODE CODE NIP (S n1 n2 -- n2 ) AX POP DX POP 1PUSH END-CODE CODE ROT (S n1 n2 n3 --- n2 n3 n1 ) DX POP BX POP AX POP BX PUSH 2PUSH END-CODE CODE -ROT (S n1 n2 n3 --- n3 n1 n2 ) BX POP AX POP DX POP BX PUSH 2PUSH END-CODE CODE FLIP (S n1 -- n2 ) AX POP AH AL XCHG 1PUSH END-CODE : ?DUP (S n -- [n] n ) DUP IF DUP THEN ; \ 16 bit Stack Operations 11OCT83HHLCODE R> (S -- n ) 0 [RP] AX MOV RP INC RP INC 1PUSH END-CODE CODE >R (S n -- ) AX POP RP DEC RP DEC AX 0 [RP] MOV NEXT END-CODE CODE R@ (S -- n ) 0 [RP] AX MOV 1PUSH END-CODE CODE PICK (S nm ... n2 n1 k -- nm ... n2 n1 nk ) BX POP BX SHL SP BX ADD 0 [BX] AX MOV 1PUSH END-CODE : ROLL (S n1 n2 .. nk n -- wierd ) >R R@ PICK SP@ DUP 2+ R> 1+ 2* CMOVE> DROP ; \ 16 bit Logical Operations 22Aug83mapCODE AND (S n1 n2 -- n3 ) BX POP AX POP BX AX AND 1PUSH END-CODE CODE OR (S n1 n2 -- n3 ) BX POP AX POP BX AX OR 1PUSH END-CODE CODE XOR (S n1 n2 -- n3 ) BX POP AX POP BX AX XOR 1PUSH END-CODE CODE NOT (S n -- n' ) AX POP AX NOT 1PUSH END-CODE -1 CONSTANT TRUE 0 CONSTANT FALSE \ Logical Operations 19Apr84mapCODE CSET (S b addr -- ) BX POP AX POP AL 0 [BX] OR NEXT END-CODE CODE CRESET (S b addr -- ) BX POP AX POP AX NOT AL 0 [BX] AND NEXT END-CODE CODE CTOGGLE (S b addr -- ) BX POP AX POP AL 0 [BX] XOR NEXT END-CODE CODE ON (S addr -- ) BX POP TRUE # 0 [BX] MOV NEXT END-CODE CODE OFF (S addr -- ) BX POP FALSE # 0 [BX] MOV NEXT END-CODE \ 16 bit Arithmetic Operations 11OCT83HHLCODE + (S n1 n2 -- sum ) BX POP AX POP BX AX ADD 1PUSH END-CODE CODE NEGATE (S n -- n' ) AX POP AX NEG 1PUSH END-CODE CODE - (S n1 n2 -- n1-n2 ) BX POP AX POP BX AX SUB 1PUSH END-CODE CODE ABS (S n -- n ) AX POP AX AX OR 0< IF AX NEG THEN 1PUSH END-CODE CODE +! (S n addr -- ) BX POP AX POP AX 0 [BX] ADD NEXT END-CODE 0 CONSTANT 0 1 CONSTANT 1 2 CONSTANT 2 3 CONSTANT 3 \ 16 bit Arithmetic Operations 11OCT83HHLCODE 2* (S n -- 2*n ) AX POP AX SHL 1PUSH END-CODE CODE 2/ (S n -- n/2 ) AX POP AX SAR 1PUSH END-CODE CODE U2/ (S u -- u/2 ) AX POP AX SHR 1PUSH END-CODE CODE 8* (S n -- 8*n ) AX POP AX SHL AX SHL AX SHL 1PUSH END-CODE CODE 1+ AX POP AX INC 1PUSH END-CODE CODE 2+ AX POP AX INC AX INC 1PUSH END-CODE CODE 1- AX POP AX DEC 1PUSH END-CODE CODE 2- AX POP AX DEC AX DEC 1PUSH END-CODE \ 16 bit Arithmetic Operations Unsigned Multiply 22Aug83mapCODE UM* (S n1 n2 -- d ) AX POP BX POP BX MUL DX AX XCHG 2PUSH END-CODE : U*D (S n1 n2 -- d ) UM* ; \ 16 bit Arithmetic Operations Unsigned Divide 22Aug83mapCODE UM/MOD (S d1 n1 -- Remainder Quotient ) BX POP DX POP AX POP BX DX CMP >= ( divide by zero? ) IF -1 # AX MOV AX DX MOV 2PUSH THEN BX DIV 2PUSH END-CODE \ 16 bit Comparison Operations 04OCT83HHLASSEMBLER LABEL YES TRUE # AX MOV 1PUSH LABEL NO FALSE # AX MOV 1PUSH CODE 0= (S n -- f ) AX POP AX AX OR YES JE NO #) JMP END-CODE CODE 0< (S n -- f ) AX POP AX AX OR YES JS NO #) JMP END-CODE CODE 0> (S n -- f ) AX POP AX AX OR YES JG NO #) JMP END-CODE CODE 0<> (S n -- f ) AX POP AX AX OR YES JNE NO #) JMP END-CODE CODE = (S n1 n2 -- f ) AX POP BX POP AX BX CMP YES JE NO #) JMP END-CODE : <> (S n1 n2 -- f ) = NOT ; : ?NEGATE (S n1 n2 -- n3 ) 0< IF NEGATE THEN ; \ 16 bit Comparison Operations 11OCT83HHLASSEMBLER LABEL YES TRUE # AX MOV 1PUSH CODE U< (S n1 n2 -- f ) AX POP BX POP AX BX CMP YES JB NO #) JMP END-CODE CODE U> (S n1 n2 -- f ) AX POP BX POP BX AX CMP YES JB NO #) JMP END-CODE CODE < (S n1 n2 -- f ) AX POP BX POP AX BX CMP YES JL NO #) JMP END-CODE CODE > (S n1 n2 -- f ) AX POP BX POP AX BX CMP YES JG NO #) JMP END-CODE : MIN (S n1 n2 -- n3 ) 2DUP > IF SWAP THEN DROP ; : MAX (S n1 n2 -- n3 ) 2DUP < IF SWAP THEN DROP ; : BETWEEN (S n1 min max -- f ) >R OVER > SWAP R> > OR NOT ; : WITHIN (S n1 min max -- f ) 1- BETWEEN ; \ 32 bit Memory Operations 13Apr84mapCODE 2@ (S addr -- d ) BX POP 0 [BX] AX MOV BX INC BX INC 0 [BX] DX MOV 2PUSH END-CODE CODE 2! (S d addr -- ) BX POP 0 [BX] POP BX INC BX INC 0 [BX] POP NEXT END-CODE \ 32 bit Memory and Stack Operations 11OCT83HHLCODE 2DROP (S d -- ) AX POP AX POP NEXT END-CODE CODE 2DUP (S d -- d d ) AX POP DX POP DX PUSH AX PUSH 2PUSH END-CODE CODE 2SWAP (S d1 d2 -- d2 d1 ) CX POP BX POP AX POP DX POP BX PUSH CX PUSH 2PUSH END-CODE CODE 2OVER (S d2 d2 -- d1 d2 d1 ) CX POP BX POP AX POP DX POP DX PUSH AX PUSH BX PUSH CX PUSH 2PUSH END-CODE : 3DUP (S a b c -- a b c a b c ) DUP 2OVER ROT ; : 4DUP (S a b c d -- a b c d a b c d ) 2OVER 2OVER ; : 2ROT (S a b c d e f - c d e f a b ) 5 ROLL 5 ROLL ; \ 32 bit Arithmetic Operations 11OCT83HHLCODE D+ (S d1 d2 -- dsum ) AX POP DX POP BX POP CX POP CX DX ADD BX AX ADC 2PUSH END-CODE CODE DNEGATE (S d# -- d#' ) BX POP CX POP AX AX SUB AX DX MOV CX DX SUB BX AX SBB 2PUSH END-CODE CODE S>D (S n -- d ) AX POP CWD AX DX XCHG 2PUSH END-CODE CODE DABS (S d# -- d# ) DX POP DX PUSH DX DX OR ' DNEGATE @-T JS NEXT END-CODE \ 32 bit Arithmetic Operations 06Apr84mapCODE D2* (S d -- d*2 ) AX POP DX POP DX SHL AX RCL 2PUSH END-CODE CODE D2/ (S d -- d/2 ) AX POP DX POP AX SAR DX RCR 2PUSH END-CODE : D- (S d1 d2 -- d3 ) DNEGATE D+ ; : ?DNEGATE (S d1 n -- d2 ) 0< IF DNEGATE THEN ; \ 32 bit Comparison Operations 01OCT83MAP: D0= (S d -- f ) OR 0= ; : D= (S d1 d2 -- f ) D- D0= ; : DU< (S ud1 ud2 -- f ) ROT SWAP 2DUP U< IF 2DROP 2DROP TRUE ELSE <> IF 2DROP FALSE ELSE U< THEN THEN ; : D< (S d1 d2 -- f ) 2 PICK OVER = IF DU< ELSE NIP ROT DROP < THEN ; : D> (S d1 d2 -- f ) 2SWAP D< ; : DMIN (S d1 d2 -- d3 ) 4DUP D> IF 2SWAP THEN 2DROP ; : DMAX (S d1 d2 -- d3 ) 4DUP D< IF 2SWAP THEN 2DROP ; \ Mixed Mode Arithmetic 04OCT83HHL: *D (S n1 n2 -- d# ) 2DUP XOR >R ABS SWAP ABS UM* R> ?DNEGATE ; : M/MOD (S d# n1 -- rem quot ) ?DUP IF DUP >R 2DUP XOR >R >R DABS R@ ABS UM/MOD SWAP R> ?NEGATE SWAP R> 0< IF NEGATE OVER IF 1- R@ ROT - SWAP THEN THEN R> DROP THEN ; : MU/MOD (S d# n1 -- rem d#quot ) >R 0 R@ UM/MOD R> SWAP >R UM/MOD R> ; \ 16 bit multiply and divide 04OCT83HHL: * (S n1 n2 -- n3 ) UM* DROP ; : /MOD (S n1 n2 -- rem quot ) >R S>D R> M/MOD ; : / (S n1 n2 -- quot ) /MOD NIP ; : MOD (S n1 n2 -- rem ) /MOD DROP ; : */MOD (S n1 n2 n3 -- rem quot ) >R *D R> M/MOD ; : */ (S n1 n2 n3 -- n1*n2/n3 ) */MOD NIP ; \ Task Dependant USER Variables 24Mar84mapUSER DEFINITIONS VARIABLE TOS ( TOP OF STACK ) VARIABLE ENTRY ( ENTRY POINT, CONTAINS MACHINE CODE ) VARIABLE LINK ( LINK TO NEXT TASK ) VARIABLE SP0 ( INITIAL PARAMETER STACK ) VARIABLE RP0 ( INITIAL RETURN STACK ) VARIABLE DP ( DICTIONARY POINTER ) VARIABLE #OUT ( NUMBER OF CHARACTERS EMITTED ) VARIABLE #LINE ( THE NUMBER OF LINES SENT SO FAR ) VARIABLE OFFSET ( RELATIVE TO ABSOLUTE DISK BLOCK 0 ) VARIABLE BASE ( FOR NUMERIC INPUT AND OUTPUT ) VARIABLE HLD ( POINTS TO LAST CHARACTER HELD IN PAD ) VARIABLE FILE ( POINTS TO FCB OF CURRENTLY OPEN FILE ) VARIABLE IN-FILE ( POINTS TO FCB OF CURRENTLY OPEN FILE ) VARIABLE PRINTING \ System VARIABLEs 24Mar84mapDEFER EMIT ( TO ALLOW PRINT SPOOLING ) META DEFINITIONS VARIABLE SCR ( SCREEN LAST LISTED OR EDITED ) VARIABLE PRIOR ( USED FOR DICTIONARY SEARCHES ) VARIABLE STATE ( COMPILATION OR INTERPRETATION ) VARIABLE WARNING ( GIVE USER DUPLICATE WARNINGS IF ON ) VARIABLE DPL ( NUMERIC INPUT PUNCTUATION ) VARIABLE R# ( EDITING CURSOR POSITION ) VARIABLE LAST ( POINTS TO NFA OF LATEST DEFINITION ) VARIABLE CSP ( HOLDS STACK POINTER FOR ERROR CHECKING ) VARIABLE CURRENT ( VOCABULARY WHICH GETS DEFINITIONS ) 8 CONSTANT #VOCS ( THE NUMBER OF VOCABULARIES TO SEARCH ) VARIABLE CONTEXT ( VOCABULARY SEARCHED FIRST ) HERE THERE #VOCS 2* DUP ALLOT ERASE \ System Variables 08Jan84mapVARIABLE 'TIB ( ADDRESS OF TERMINAL INPUT BUFFER ) VARIABLE WIDTH ( WIDTH OF NAME FIELD ) VARIABLE VOC-LINK ( POINTS TO NEWEST VOCABULARY ) VARIABLE BLK ( BLOCK NUMBER TO INTERPRET ) VARIABLE >IN ( OFFSET INTO INPUT STREAM ) VARIABLE SPAN ( NUMBER OF CHARACTERS EXPECTED ) VARIABLE #TIB ( NUMBER OF CHARACTERS TO INTERPRET ) VARIABLE END? ( TRUE IF INPUT STREAM EXHAUSTED ) \ Devices Strings 04OCT83HHL 32 CONSTANT BL 8 CONSTANT BS 7 CONSTANT BELL VARIABLE CAPS CODE FILL ( start-addr count char -- ) CLD DS AX MOV AX ES MOV AX POP CX POP DI POP REP AL STOS NEXT END-CODE : ERASE (S addr len -- ) 0 FILL ; : BLANK (S addr len -- ) BL FILL ; CODE COUNT (S addr -- addr+1 len ) BX POP AX AX SUB 0 [BX] AL MOV BX INC BX PUSH 1PUSH END-CODE CODE LENGTH (S addr -- addr+2 len ) BX POP 0 [BX] AX MOV BX INC BX INC BX PUSH 1PUSH END-CODE : MOVE ( from to len -- ) -ROT 2DUP U< IF ROT CMOVE> ELSE ROT CMOVE THEN ; \ Devices Strings